import asyncio
import logging
import logging.config
import pytz
from pathlib import Path
from datetime import datetime
from logging.handlers import QueueHandler


class CustomFormatter(logging.Formatter):
    def formatTime(self, record, datefmt=None):
        local_time = datetime.fromtimestamp(record.created, pytz.timezone('Asia/Shanghai'))
        if datefmt:
            return local_time.strftime(datefmt)
        return local_time.strftime("%Y-%m-%d %H:%M:%S")


class AsyncQueueHandler(QueueHandler):
    def __init__(self, queue: asyncio.Queue, logger: logging.Logger):
        super().__init__(queue)
        self.logger = logger  # 添加 logger 参数，用于记录队列相关信息

    def emit(self, record):
        try:
            if self.queue.full():
                # 如果队列已满，记录警告日志
                self.logger.warning("队列已满，等待空余空间，日志丢失将避免")
                # 阻塞等待队列有空余空间
                self.queue.put(record)  # await 阻塞等待
            else:
                super().emit(record)  # 确保异步操作被 await
        except Exception as e:
            # 捕获并记录异常，防止日志丢失
            self.logger.error(f"日志处理异常: {e}")


class LogManager:
    def __init__(self, max_queue_size: int = 100):
        self.log_queue = asyncio.Queue(maxsize=max_queue_size)
        self.queue_handler = AsyncQueueHandler(self.log_queue, self.log_queue)
        self.logger = logging.getLogger(__name__)
        self.logger.addHandler(self.queue_handler)
        self.logger.setLevel(logging.INFO)

        # 创建事件循环并启动日志监听
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)
        self.listener_task = self.loop.create_task(self._log_listener())

    async def register(self, log_path: Path, log_name: str, error_name: str):
        await self._setup_log_config(log_path, log_name, error_name)

    async def _setup_log_config(self, log_path: Path, log_name: str, error_name: str):
        if not log_path.exists():
            log_path.mkdir(parents=True, exist_ok=True)
        log_file_path = log_path.joinpath(log_name)
        error_file_path = log_path.joinpath(error_name)

        dict_config = await self._get_dict_config(log_file_path, error_file_path)
        try:
            logging.config.dictConfig(dict_config)
        except Exception as e:
            print(f"配置日志失败: {e}")

    @staticmethod
    async def _get_dict_config(log_file_path: Path, error_file_path: Path):
        return {
            'version': 1,
            'disable_existing_loggers': False,
            'formatters': {
                'precise': {
                    '()': CustomFormatter,
                    "format": "[%(asctime)s] %(levelname)s: %(pathname)s:%(lineno)d  %(message)s",
                    'datefmt': "%Y-%m-%d %H:%M:%S"
                },
            },
            'handlers': {
                'file': {
                    'filename': log_file_path,
                    'level': 'NOTSET',
                    'class': 'logging.handlers.TimedRotatingFileHandler',
                    'interval': 1,
                    'when': 'midnight',
                    'backupCount': 10,
                    'delay': True,
                    'formatter': 'precise',
                    'encoding': 'utf8',
                },
                'error_file_handler': {
                    'class': 'logging.handlers.TimedRotatingFileHandler',
                    'interval': 1,
                    'when': 'midnight',
                    'backupCount': 10,
                    'delay': True,
                    'level': 'ERROR',
                    'formatter': 'precise',
                    'filename': error_file_path,
                    'encoding': 'utf-8'
                }
            },
            'loggers': {
                '': {
                    'handlers': ['file', 'error_file_handler'],
                    'level': 'INFO',
                    'propagate': False,
                }
            },
        }

    async def _log_listener(self):
        while True:
            record = await self.loop.run_in_executor(None, self.log_queue.get)
            if record is None:
                break
            await asyncio.to_thread(self.logger.handle, record)

    async def stop_listener(self):
        self.log_queue.put_nowait(None)  # 发送停止信号
        self.loop.run_until_complete(self.listener_task)
        self.loop.close()

    async def error(self, message: str):
        self.logger.error(message)  # 正确记录错误

    async def info(self, message: str):
        self.logger.info(message)

    async def debug(self, message: str):
        self.logger.debug(message)


log_manager = LogManager()

